{-----------------------------------------------------------------

  (c) 2008-2009 Markus Dittrich 
 
  This program is free software; you can redistribute it 
  and/or modify it under the terms of the GNU General Public 
  License Version 3 as published by the Free Software Foundation. 
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License Version 3 for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 59 Temple Place - Suite 330, 
  Boston, MA 02111-1307, USA.

--------------------------------------------------------------------}

-- | this module contains the top level functions for retrieving
-- the contents of a package.
module Drivers.Content ( display_package_contents
                       , display_binary_package_contents
                       , display_doc_package_contents
                       , display_etc_package_contents
                       , display_include_package_contents
                       , display_library_package_contents
                       , display_share_package_contents 
                       , retrieve_package_content
                       ) where

-- imports
import qualified Data.ByteString as B(ByteString, null, putStrLn, 
  split)
import Prelude


-- local imports
import Helpers.ByteString(binStr, docStr, etcStr, includeStr, libStr,
  lib64Str, sbinStr, shareStr, slashW, usrStr)
import Helpers.PrettyPrint(Color(..), putColorBStrLn)
import Parsers.Content(FileType(..), PackageContentItem(..), 
  retrieve_package_content)


-- | function for displaying the full content of a package
display_package_contents :: FilePath -> IO ()
display_package_contents = display_content_dispatcher (\_ -> True) 



-- | function for displaying the binary files installed by a package
display_binary_package_contents :: FilePath -> IO ()
display_binary_package_contents = 
    display_content_dispatcher is_binary_file 



-- | function for displaying the doc files installed by a package
display_doc_package_contents :: FilePath -> IO ()
display_doc_package_contents = display_content_dispatcher is_doc_file 



-- | function for displaying the \/etc content of a package
display_etc_package_contents :: FilePath -> IO ()
display_etc_package_contents = display_content_dispatcher is_etc_file



-- | function for displaying the include files installed by a package
display_include_package_contents :: FilePath -> IO ()
display_include_package_contents =
  display_content_dispatcher is_include_file 



-- | function for displaying the library files installed by a package
display_library_package_contents :: FilePath -> IO ()
display_library_package_contents =
  display_content_dispatcher is_library_file 



-- | function for displaying the include files installed by a package
display_share_package_contents :: FilePath -> IO ()
display_share_package_contents =
  display_content_dispatcher is_share_file 



-- | dispatch the content lookup mechanism with the package filter
-- filterFunc provided by the caller
display_content_dispatcher :: (PackageContentItem -> Bool) -> FilePath
                           -> IO ()
display_content_dispatcher filterFunc targetPkg =

      retrieve_package_content targetPkg
      >>= print_content . filter filterFunc 



-- | print the list of PackageContentItem corresponding
-- to a particular file
print_content :: [PackageContentItem] -> IO ()
print_content []           = return ()
print_content (item:items) = 
  do 
    case fileType item of
      Dir -> putColorBStrLn Red $ fileName item
      Sym -> putColorBStrLn Cyan $ fileName item
      _   -> B.putStrLn $ fileName item
 
    print_content items
  
   

-- | Filter all binary files out of the complete package content,
-- i.e., everything in \/bin, \/sbin, \/usr\/bin, \/usr\/sbin
-- is shown.
is_binary_file :: PackageContentItem -> Bool
is_binary_file item 
    | B.null $ fileName item = False
    | otherwise          = match_bin $ tail $ B.split slashW 
                             $ fileName item

  where
    match_bin :: [B.ByteString] -> Bool
    match_bin []      = False
    match_bin (x:y:_) = (x == usrStr) &&
                        ((y == binStr) || (y == sbinStr))
    match_bin (x:_)   = (x == binStr) || (x == sbinStr)



-- | Filter all doc files (i.e. files in \/usr\/share\/doc)
is_doc_file :: PackageContentItem -> Bool
is_doc_file item 
    | B.null $ fileName item = False
    | otherwise          = match_bin $ tail $ B.split slashW 
                             $ fileName item

  where
    match_bin :: [B.ByteString] -> Bool
    match_bin []        = False
    match_bin (x:y:z:_) = (x == usrStr) && (y == shareStr) 
                          && (z == docStr)
    match_bin (_:_)     =  False



-- | Filter all library files out of the complete package content,
-- i.e., everything in \/lib, \/lib64, \/usr\/lib, \/usr\/lib64
-- is shown.
-- NOTE: This may return more than the actual libs since some 
-- packages install a whole host of stuff in /usr/lib. If we
-- really only want libs we could filter out the *.so and such
is_library_file :: PackageContentItem -> Bool
is_library_file item 
    | B.null $ fileName item = False
    | otherwise          = match_bin $ tail $ B.split slashW 
                             $ fileName item

  where
    match_bin :: [B.ByteString] -> Bool
    match_bin []      = False
    match_bin (x:y:_) = (x == usrStr) &&
                        ((y == libStr) || (y == lib64Str))
    match_bin (x:_)   = (x == libStr) || (x == lib64Str)



-- | Filter all files in \/usr\/include out of the complete 
-- package content,
is_include_file :: PackageContentItem -> Bool
is_include_file item 
    | B.null $ fileName item = False
    | otherwise          = match_bin $ tail $ B.split slashW 
                             $ fileName item

  where
    match_bin :: [B.ByteString] -> Bool
    match_bin []      = False
    match_bin (x:y:_) = (x == usrStr) && (y == includeStr) 
    match_bin _       = False



-- | Filter all files in \/etc out of the complete package content
is_etc_file :: PackageContentItem -> Bool
is_etc_file item 
    | B.null $ fileName item = False
    | otherwise          = match_bin $ tail $ B.split slashW 
                             $ fileName item

  where
    match_bin :: [B.ByteString] -> Bool
    match_bin []      = False
    match_bin (x:_)   = (x == etcStr)



-- | Filter all files in \/usr\/share out of the complete package 
-- content
is_share_file :: PackageContentItem -> Bool
is_share_file item 
    | B.null $ fileName item = False
    | otherwise          = match_bin $ tail $ B.split slashW 
                             $ fileName item

  where
    match_bin :: [B.ByteString] -> Bool
    match_bin []        = False
    match_bin (x:y:_)   = (x == usrStr) && (y == shareStr)
    match_bin _         = False



